package io.shuttle.mbe.api

import io.shuttle.mbe.api.annotation.ChromeMinVersion
import io.shuttle.mbe.api.annotation.PromiseStyleMinVersion
import io.shuttle.mbe.api.types.ImageData
import io.shuttle.mbe.api.types.StringOrColorArray
import io.shuttle.mbe.api.types.Value1Function
import io.shuttle.mbe.api.types.VoidFunction
import io.shuttle.mbe.core.Promise

////////////////////
// Browser Action
////////////////////
/**
 * Use browser actions to put icons in the main Google Chrome toolbar, to the right of the address bar. In addition to its icon, a browser action can have a tooltip, a badge, and a popup.
 *
 * Manifest: "browser_action"
 *
 * MV2 only
 */
interface BrowserAction {
    /**
     * @since Chrome 22
     * Disables the browser action for a tab.
     * @param tabId The id of the tab for which you want to modify the browser action.
     * @param callback Supported since Chrome 67
     * @return The `disable` method provides its result via callback or returned as a `Promise` (MV3 only). It has no parameters.
     */
    @PromiseStyleMinVersion(88)
    fun disable(
        // The ID of the tab for which to modify the browser action.
        tabId: Number? = null,
        @ChromeMinVersion(67)
        callback: VoidFunction? = null
    ): Promise<Void>

    /**
     * @since Chrome 22
     * Enables the browser action for a tab. By default, browser actions are enabled.
     * @param tabId The id of the tab for which you want to modify the browser action.
     * @return The `enable` method provides its result via callback or returned as a `Promise` (MV3 only). It has no parameters.
     */
    @ChromeMinVersion(22)
    @PromiseStyleMinVersion(88)
    fun enable(
        // The ID of the tab for which to modify the browser action.
        tabId: Number? = null,
        @ChromeMinVersion(67)
        callback: VoidFunction? = null
    ): Promise<Void>

    /**
     * @since Chrome 19
     * Gets the background color of the browser action.
     * @return The `getBadgeBackgroundColor` method provides its result via callback or returned as a `Promise` (MV3 only).
     */
    @PromiseStyleMinVersion(88)
    fun getBadgeBackgroundColor(
        details: TabDetails,
        callback: Value1Function<ColorArray>? = null
    ): Promise<ColorArray>

    /**
     * @since Chrome 19
     * Gets the badge text of the browser action. If no tab is specified, the non-tab-specific badge text is returned.
     * @param callback Supported since Chrome 67
     * @return The `getBadgeText` method provides its result via callback or returned as a `Promise` (MV3 only).
     */
    @PromiseStyleMinVersion(88)
    @ChromeMinVersion(19)
    fun getBadgeText(
        details: TabDetails,
        callback: Value1Function<String>? = null
    ): Promise<String>

    /**
     * @since Chrome 19
     * Gets the html document set as the popup for this browser action.
     * @return The `getPopup` method provides its result via callback or returned as a `Promise` (MV3 only).
     */
    @PromiseStyleMinVersion(88)
    fun getPopup(
        details: TabDetails,
        callback: Value1Function<String>? = null
    ): Promise<String>

    /**
     * @since Chrome 19
     * Gets the title of the browser action.
     * @return The `getTitle` method provides its result via callback or returned as a `Promise` (MV3 only).
     */
    @PromiseStyleMinVersion(88)
    fun getTitle(
        details: TabDetails,
        callback: Value1Function<String>? = null
    ): Promise<String>

    /**
     * Sets the background color for the badge.
     * @param callback Supported since Chrome 67
     * @return The `setBadgeBackgroundColor` method provides its result via callback or returned as a `Promise` (MV3 only). It has no parameters.
     */
    @PromiseStyleMinVersion(88)
    fun setBadgeBackgroundColor(
        details: TabDetailsColor,
        @ChromeMinVersion(67)
        callback: VoidFunction? = null
    ): Promise<Void>

    /**
     * Sets the badge text for the browser action. The badge is displayed on top of the icon.
     * @param callback Supported since Chrome 67
     * @return The `setBadgeText` method provides its result via callback or returned as a `Promise` (MV3 only). It has no parameters.
     */
    @PromiseStyleMinVersion(88)
    fun setBadgeText(
        details: BadgeTextDetails,
        @ChromeMinVersion(67)
        callback: VoidFunction? = null
    ): Promise<Void>

    /**
     * Sets the icon for the browser action. The icon can be specified either as the path to an image file or as the pixel data from a canvas element, or as dictionary of either one of those. Either the path or the imageData property must be specified.
     */
    @PromiseStyleMinVersion(88)
    fun setIcon(
        details: TabIconDetails,
        callback: VoidFunction? = null
    ): Promise<Void>

    /**
     * Sets the html document to be opened as a popup when the user clicks on the browser action's icon.
     * @param callback Supported since Chrome 67
     * @return The `setPopup` method provides its result via callback or returned as a `Promise` (MV3 only). It has no parameters.
     */
    @PromiseStyleMinVersion(88)
    fun setPopup(
        details: PopupDetails,
        @ChromeMinVersion(67)
        callback: VoidFunction? = null
    ): Promise<Void>

    /**
     * Sets the title of the browser action. This shows up in the tooltip.
     * @param callback Supported since Chrome 67
     * @return The `setTitle` method provides its result via callback or returned as a `Promise` (MV3 only). It has no parameters.
     */
    @PromiseStyleMinVersion(88)
    fun setTitle(
        details: TitleDetails,
        @ChromeMinVersion(67)
        callback: VoidFunction? = null
    ): Promise<Void>

    // Fired when a browser action icon is clicked. Does not fire if the browser action has a popup.
    val onClicked: Events.Event<Value1Function<Tabs.Tab>>

    @ChromeMinVersion(88)
    data class TabDetails(
        // The ID of the tab to query state for. If no tab is specified, the non-tab-specific state is returned.
        var tabId: Number? = null,
    )

    data class BadgeBackgroundColorDetails(
        /** An array of four integers in the range [0,255] that make up the RGBA color of the badge. For example, opaque red is [255, 0, 0, 255]. Can also be a string with a CSS value, with opaque red being #FF0000 or #F00. */
        var color: StringOrColorArray,
        /** Optional. Limits the change to when a particular tab is selected. Automatically resets when the tab is closed.  */
        var tabId: Number?
    )

    data class TabDetailsColor(
        // An array of four integers in the range 0-255 that make up the RGBA color of the badge.
        // Can also be a string with a CSS hex color value;
        // for example, #FF0000 or #F00 (red). Renders colors at full opacity.
        var color: ColorOrColorArr,
        // Limits the change to when a particular tab is selected. Automatically resets when the tab is closed.
        var tabId: Number? = null,
    )

    data class BadgeTextDetails(
        // Any number of characters can be passed, but only about four can fit into the space.
        // If an empty string ('') is passed, the badge text is cleared.
        // If tabId is specified and text is null,
        // the text for the specified tab is cleared and defaults to the global badge text.
        var text: String? = null,
        // Limits the change to when a particular tab is selected. Automatically resets when the tab is closed.
        var tabId: Number? = null,
    )

    data class TabIconDetails(
        // Either an ImageData object or a dictionary {size -> ImageData} representing an icon to be set.
        // If the icon is specified as a dictionary, the image used is chosen depending on the screen's pixel density.
        // If the number of image pixels that fit into one screen space unit equals scale,
        // then an image with size scale * n is selected, where n is the size of the icon in the UI.
        // At least one image must be specified.
        // Note that 'details.imageData = foo' is equivalent to 'details.imageData = {'16': foo}'
        val imageData: ImageDataOrAny? = null,
        // Either a relative image path or a dictionary {size -> relative image path} pointing to an icon to be set.
        // If the icon is specified as a dictionary, the image used is chosen depending on the screen's pixel density.
        // If the number of image pixels that fit into one screen space unit equals scale,
        // then an image with size scale * n is selected, where n is the size of the icon in the UI.
        // At least one image must be specified. Note that 'details.path = foo' is equivalent to 'details.path = {'16': foo}'
        val path: PathOrAny? = null,
        // Limits the change to when a particular tab is selected. Automatically resets when the tab is closed.
        var tabId: Number? = null,
    )

    data class PopupDetails(
        // The relative path to the HTML file to show in a popup. If set to the empty string (''), no popup is shown.
        val popup: String,
        // Limits the change to when a particular tab is selected. Automatically resets when the tab is closed.
        val tabId: Number? = null,
    )

    data class TitleDetails(
        // The string the browser action should display when moused over.
        var title: String,
        // Limits the change to when a particular tab is selected. Automatically resets when the tab is closed.
        var tabId: Number? = null,
    )

    sealed class ImageDataOrAny {
        data class ImageData1(val imageData: ImageData) : ImageDataOrAny()
        data class Any1(val any: Any) : ImageDataOrAny()
    }

    sealed class PathOrAny {
        data class Path(val path: String) : PathOrAny()
        data class Any1(val any: Any) : PathOrAny()
    }

    sealed class ColorOrColorArr {
        data class Color(val colorString: String) : ColorOrColorArr()
        data class ColorArr(val colorArray: ColorArray) :
            ColorOrColorArr()
    }
}